﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using Ionic.Zip;
using MSDNWebcast.Properties;
using MSDNWebcast.Utils;

namespace MSDNWebcast.Models
{
    /// <summary>
    /// 课件（PPT, Video）
    /// </summary>
    public class CourseFile : INotifyPropertyChanged
    {
        private string m_FolderPath;

        public CourseFile(Course course, FileType fileType)
        {
            Course = course;
            FileType = fileType;
        }

        /// <summary>
        /// 课程
        /// </summary>
        public Course Course { get; private set; }

        /// <summary>
        /// 课件类型
        /// </summary>
        public FileType FileType { get; private set; }

        /// <summary>
        /// 课件已下载并可打开
        /// </summary>
        public bool CanOpen
        {
            get
            {
                var directoryExited = Directory.Exists(FolderPath);
                if (directoryExited) return true;
                var directory = Path.GetDirectoryName(FolderPath);
                if (!Directory.Exists(directory)) return false;
                var files = Directory.GetFiles(directory, String.Format("{0}.*", FileType.ID));
                return files.Length > 0;
            }
        }

        /// <summary>
        /// 能够播放
        /// </summary>
        public bool CanPlay
        {
            get { return CanOpen && FileType.CanPlay; }
        }

        /// <summary>
        /// 文件夹路径
        /// </summary>
        public string FolderPath
        {
            get
            {
                if (m_FolderPath == null)
                {
                    m_FolderPath = String.Format(@"{0}\{1}\{2}\{3}", Settings.Default.DownloadPath, Course.Series, Course.Headline, FileType.ID);
                    RemoveInvalidChars();
                }
                return m_FolderPath;
            }
        }

        /// <summary>
        /// 文件路径
        /// </summary>
        public string FilePath
        {
            get
            {
                if (!CanPlay)
                    throw new Exception("文件不存在！");
                var directory = Path.GetDirectoryName(FolderPath);
                var files = Directory.GetFiles(directory, String.Format("{0}.*", FileType.ID));
                return files[0];
            }
        }

        /// <summary>
        /// 返回临时下载的文件路径
        /// </summary>
        public string TempFilePath
        {
            get
            {
                return String.Format(@"{0}\{1}.{2}.{3}", Settings.Default.DownloadPath, Course.EventID, FileType.ID, "td");
            }
        }

        /// <summary>
        /// 下载地址
        /// </summary>
        public String Url
        {
            get
            {
                return string.Format("{0}?id={1}&type={2}", Settings.Default.WebcastURL, Course.EventID, FileType.ID);
            }
        }

        public void RemoveInvalidChars()
        {
            foreach (char c in Path.GetInvalidPathChars())
            {
                m_FolderPath = m_FolderPath.Replace(c.ToString(), "");
            }
        }

        public override bool Equals(object obj)
        {
            if (obj != null && obj is CourseFile && !ReferenceEquals(obj, this))
                return ((CourseFile)obj).FileType.ID == this.FileType.ID && ((CourseFile)obj).Course == this.Course;
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// 解压临时文件
        /// </summary>
        internal void UnZip()
        {
            var worker = new BackgroundWorker {WorkerSupportsCancellation = true};
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
            worker.DoWork += worker_DoWork;
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// 打开文件
        /// </summary>
        internal void Open()
        {
            if (Directory.Exists(FolderPath))
                Process.Start("explorer.exe", FolderPath);
            else
            {
                var directory = Path.GetDirectoryName(FolderPath);
                var files = Directory.GetFiles(directory, String.Format("{0}.*", FileType.ID));
                Process.Start(files[0]);
            }
        }

        /// <summary>
        /// 解压文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            bool isSingleFile = false;
            string fileName = "";
            using (var zipFile = new ZipFile())
            {
                try
                {
                    zipFile.Initialize(TempFilePath);
                    if (zipFile.Count < 1)
                        throw new Exception("压缩文件不正确，无法解压！");
                }
                catch (ZipException)
                {
                    throw new Exception("压缩文件不正确，无法解压！");
                }

                if (zipFile.Count == 1)
                {
                    isSingleFile = true;
                    fileName = FolderPath + Path.GetExtension(zipFile[0].FileName);
                }
            }

            if (isSingleFile)
                ZipUtil.UnZipFile(TempFilePath, fileName, true);
            else
                ZipUtil.UnZipFiles(TempFilePath, FolderPath, true);
        }

        /// <summary>
        /// 解压文件完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            OnPropertyChanged("CanOpen");
        }

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 触发事件
        /// </summary>
        /// <param name="propertyName"></param>
        private void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;
                throw new Exception(msg);
            }
        }
    }
}
